{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# A Simple MNIST model\n",
    "\n",
    "A digit recognition model implemented with Tensorflow and Python.\n",
    "\n",
    "Adapted from: https://github.com/sethjuarez/SimpleMNIST\n",
    "\n",
    "## Requirements\n",
    "\n",
    "* Anaconda\n",
    "* Tensorflow\n",
    "* Azure Machine Learning\n",
    "\n",
    "## Setup instructions\n",
    "\n",
    "See: [Configure a development environment for Azure Machine Learning](https://docs.microsoft.com/en-us/azure/machine-learning/service/how-to-configure-environment?WT.mc_id=AILive-workshop-davidsmi)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "import json\n",
    "import time\n",
    "import azureml\n",
    "import logging\n",
    "from azureml.core.model import Model\n",
    "from azureml.train.automl import AutoMLConfig\n",
    "from azureml.core import Workspace, Run, Datastore, Experiment\n",
    "from azureml.core.runconfig import RunConfiguration\n",
    "from azureml.core.conda_dependencies import CondaDependencies\n",
    "from azureml.core.compute import ComputeTarget, AmlCompute\n",
    "from azureml.core.compute_target import ComputeTargetException\n",
    "from azureml.train.hyperdrive import *\n",
    "from azureml.train.dnn import TensorFlow\n",
    "from azureml.widgets import RunDetails\n",
    "\n",
    "print(\"Azure ML SDK Version: \", azureml.core.VERSION)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You will need to provide a `config.json` file in the working folder to provide keys for your Azure ML workspace. See Seup Instructions above for details."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# use this code to set up config file\n",
    "#subscription_id ='<SUB_ID>'\n",
    "#resource_group ='<RESOURCE_GROUP>'\n",
    "#workspace_name = '<WORKSPACE>'\n",
    "\n",
    "#try:\n",
    "#   ws = Workspace(subscription_id = subscription_id, resource_group = resource_group, workspace_name = workspace_name)\n",
    "#   ws.write_config()\n",
    "#   print('Workspace configuration succeeded. You are all set!')\n",
    "#except:\n",
    "#   print('Workspace not found. TOO MANY ISSUES!!!')\n",
    "ws = Workspace.from_config()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Compute Environment"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cluster = 'sauron'\n",
    "try:\n",
    "    compute = ComputeTarget(workspace=ws, name=cluster)\n",
    "    print('Found existing compute target')\n",
    "except ComputeTargetException:\n",
    "    print('Creating a new compute target...')\n",
    "    compute_config = AmlCompute.provisioning_configuration(vm_size='STANDARD_NC6', min_nodes=1, max_nodes=6)\n",
    "    compute = ComputeTarget.create(ws, cluster, compute_config)\n",
    "    compute.wait_for_completion(show_output=True)\n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Run Experiment"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Create and run experiment\n",
    "mnist = Experiment(ws, 'dms-simplemnist')\n",
    "estimator = TensorFlow(source_directory='.',\n",
    "                       compute_target=compute,\n",
    "                       entry_script='train.py',\n",
    "                       use_gpu=True)\n",
    "\n",
    "run = mnist.submit(estimator)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "run"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "RunDetails(run).show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Manage Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ds = ws.get_default_datastore()\n",
    "mnist_data = ds.upload(src_dir = 'data', target_path = 'mnist', show_progress = True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# run the same was as above\n",
    "script_params={\n",
    "    '--data': mnist_data.as_mount(),\n",
    "}\n",
    "\n",
    "# Create and run experiment\n",
    "mnist = Experiment(ws, 'simplemnist')\n",
    "estimator = TensorFlow(source_directory='.',\n",
    "                       compute_target=compute,\n",
    "                       entry_script='train.py',\n",
    "                       script_params=script_params,\n",
    "                       use_gpu=True)\n",
    "\n",
    "run = mnist.submit(estimator)\n",
    "RunDetails(run).show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Optimize hyperparameters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# same as above but increase the max_steps and remove the parameters\n",
    "script_params={\n",
    "    '--data': mnist_data,\n",
    "    '--epochs': 100\n",
    "}\n",
    "\n",
    "mnist = Experiment(ws, 'simplemnist')\n",
    "estimator = TensorFlow(source_directory='.',\n",
    "                       compute_target=compute,\n",
    "                       entry_script='train.py',\n",
    "                       script_params=script_params,\n",
    "                       use_gpu=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## hyperparameter search"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "ps = RandomParameterSampling(\n",
    "    {\n",
    "        '--lr': loguniform(-15, -3),\n",
    "        '--batch': choice(16, 32, 64, 128, 512)\n",
    "    }\n",
    ")\n",
    "\n",
    "early_termination_policy = BanditPolicy(slack_factor = 0.15, evaluation_interval=2)\n",
    "\n",
    "hyperdrive_run_config = HyperDriveRunConfig(estimator = estimator, \n",
    "                                            hyperparameter_sampling = ps, \n",
    "                                            policy = early_termination_policy,\n",
    "                                            primary_metric_name = \"accuracy\",\n",
    "                                            primary_metric_goal = PrimaryMetricGoal.MAXIMIZE,\n",
    "                                            max_total_runs = 20,\n",
    "                                            max_concurrent_runs = 5)\n",
    "\n",
    "hd_run = mnist.submit(hyperdrive_run_config)\n",
    "\n",
    "RunDetails(hd_run).show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Deploy best model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "best = hd_run.get_best_run_by_primary_metric()\n",
    "best.get_file_names()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "best.download_file(name='outputs/digits.pb', output_file_path='outputs')\n",
    "model_file = 'outputs/digits.pb'\n",
    "model = Model.register(ws, model_name='SimpleMNIST', model_path=model_file, \n",
    "                       description='Simple MNIST model extracted from hyperparamter optimization run')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Create Conda Deps"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from azureml.core.conda_dependencies import CondaDependencies\n",
    "myenv = CondaDependencies()\n",
    "\n",
    "myenv.add_pip_package('numpy')\n",
    "myenv.add_tensorflow_pip_package()\n",
    "\n",
    "with open('simplemnist.yml','w') as f:\n",
    "    print('Writing out {}'.format('simplemnist.yml'))\n",
    "    f.write(myenv.serialize_to_string())\n",
    "    print('Done!')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Create Image"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "model = ws.models['SimpleMNIST']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from azureml.core.image import ContainerImage, Image\n",
    "image_config = ContainerImage.image_configuration(execution_script=\"score.py\", \n",
    "                                    runtime=\"python\", \n",
    "                                    conda_file=\"simplemnist.yml\")\n",
    "\n",
    "\n",
    "image = Image.create(ws, 'simplemnist', [model], image_config)\n",
    "image.wait_for_creation(show_output=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "image.image_build_log_uri"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Deploy Service"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from azureml.core.webservice import AciWebservice\n",
    "from azureml.core.webservice import Webservice\n",
    "\n",
    "aciconfig = AciWebservice.deploy_configuration(cpu_cores=1, \n",
    "                                               memory_gb=1, \n",
    "                                               description='simple MNIST digit detection')\n",
    "service = Webservice.deploy_from_image(workspace=ws, \n",
    "                                       image=image, \n",
    "                                       name='simplemnist-svc', \n",
    "                                       deployment_config=aciconfig)\n",
    "service.wait_for_deployment(show_output=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "service.scoring_uri"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "with open('deploy.log','w') as f:\n",
    "    f.write(service.get_logs())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Automatic Machine Learning"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "automl_settings = {\n",
    "    \"name\": \"AutoML_Demo_Experiment_{0}\".format(time.time()),\n",
    "    \"iteration_timeout_minutes\": 5,\n",
    "    \"iterations\": 20,\n",
    "    \"n_cross_validations\": 5,\n",
    "    \"primary_metric\": 'AUC_weighted',\n",
    "    \"preprocess\": False,\n",
    "    \"max_concurrent_iterations\": 10,\n",
    "    \"verbosity\": logging.INFO\n",
    "}\n",
    "\n",
    "automl_config = AutoMLConfig(task='classification',\n",
    "                             debug_log='automl_errors.log',\n",
    "                             path='.',\n",
    "                             compute_target = compute,\n",
    "                             data_script='./get_data.py',\n",
    "                             **automl_settings)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "experiment=Experiment(ws, 'simplemnist')\n",
    "remote_run = experiment.submit(automl_config)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "RunDetails(remote_run).show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
